package com.lry.pda.bottom.c.backend.type;

import com.lry.pda.bottom.c.backend.IValueSetter;
import lombok.Data;

import java.util.Objects;

//https://blog.csdn.net/tyler_download/article/details/52511911
@Data
public class Symbol implements IValueSetter {

    public static final String SCOPE = "global";

    //变量的名字
    private String name;

    //变量的嵌套层次
    private int level;

    //如果symbol是函数，args是参数列表
    private Symbol args;

    //指向下一个同level的symbol
    private Symbol next;

    //指向第一个specifier,类型int，long。。。
    private TypeLink typeLinkBegin;

    private Object value;

    //指向最后的declarator,指针，数组，或函数
    private TypeLink typeLinkEnd;

    private String scope = SCOPE;


    public Symbol(String name, int level) {
        this.name = name;
        this.level = level;
    }

    public Symbol copy() {
        Symbol symbol = new Symbol(this.name, this.level);
        symbol.args = this.args;
        symbol.next = this.next;
        symbol.typeLinkBegin = this.typeLinkBegin;
        symbol.typeLinkEnd = this.typeLinkEnd;
        symbol.scope = this.scope;
        return symbol;
    }

    public int getByteSize() {
        int size = 0;
        Specifier sp = typeLinkBegin.getSpecifier();
        if (sp.getType() == Specifier.LONG ||
            sp.getType() == Specifier.DOUBLE) {
            size = 8;
        } else if(sp.getType()==Specifier.INT
                ||sp.getType()==Specifier.FLOAT){
            size = 4;
        }else if(sp.getType()==Specifier.SHORT){
            size = 2;
        }else if(sp.getType()==Specifier.BOOLEAN
                ||sp.getType()==Specifier.CHAR){
            size = 1;
        }
        return size;
    }

    public void addTypeLink(TypeLink typeLink){
        if(null==typeLinkBegin){
            typeLinkBegin = typeLink;
            typeLinkEnd = typeLink;
        }else{
            typeLink.setNext(typeLinkBegin);
            typeLinkBegin = typeLink;
        }
    }

    /**
     * 通过类型获取Declarator
     * @param declareType array，pointer，func
     * @return Declarator
     */
    public Declarator getDeclarator(int declareType){
        TypeLink begin = typeLinkBegin;
        while(null!=begin){
            if(null==begin.getDeclarator()){
                begin = begin.getNext();
                continue;
            }
            if(declareType == begin.getDeclarator().getType()){
                return begin.getDeclarator();
            }
            begin = begin.getNext();
        }
        return null;
    }

    /**
     * 通过类型获取Specifier
     * @param specifierType int long struct....
     * @return Specifier
     */
    public Specifier getSpecifier(int specifierType) {
        if(null!=typeLinkBegin.getSpecifier()){
            if(specifierType == typeLinkBegin.getSpecifier().getType()){
                return typeLinkBegin.getSpecifier();
            }
        }
        return null;
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Symbol symbol = (Symbol) o;
        return level == symbol.level && Objects.equals(name, symbol.name) && Objects.equals(scope, symbol.scope);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, level, scope);
    }

    @Override
    public void setValue(Object obj)  {
        System.out.println("Assign Value of " + obj.toString() + " to Variable " + name);
        this.value = obj;
    }
}
